package com.gitee.wsl.compose.ui.calendar


import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import com.gitee.wsl.compose.ui.calendar.config.SelectionMode
import com.gitee.wsl.compose.ui.calendar.config.SelectionResult
import com.gitee.wsl.compose.ui.calendar.range.RangeConfig
import com.gitee.wsl.ext.base.betweenInterval
import com.gitee.wsl.ext.base.today
import com.gitee.wsl.ext.set.addOrRemove
import kotlinx.datetime.LocalDate

interface CalendarAdapter {

    val rangeConfig: RangeConfig

    val selectionMode: SelectionMode

    fun isSelected(date: LocalDate): Boolean = false

    fun isSelectedRangeInterval(date: LocalDate): Boolean = false

    fun changeSelected(date: LocalDate)

    fun isActiveDay(date: LocalDate): Boolean = false

    fun isEnabled(date: LocalDate): Boolean = true

    fun getSelectionResult(): SelectionResult = SelectionResult.None
}

typealias DateDisableCheck = (date: LocalDate) -> Boolean

fun CalendarAdapter(
    selected: SnapshotStateList<LocalDate> = mutableStateListOf() ,
    disableCheck: DateDisableCheck = { false },
    rangeConfig: RangeConfig = RangeConfig(),
    selectionMode: SelectionMode = SelectionMode.Single,
): CalendarAdapter = CalendarAdapterImpl(
    selected,
    disableCheck,
    rangeConfig,
    selectionMode,
)

internal class CalendarAdapterImpl(
    private val selected: SnapshotStateList<LocalDate> = mutableStateListOf(),
    private val disableDays:DateDisableCheck = { false },
    override val rangeConfig: RangeConfig = RangeConfig(),
    override val selectionMode: SelectionMode = SelectionMode.Single,
    ) : CalendarAdapter {

    private var activeDay: LocalDate = today

    override fun isSelected(date: LocalDate): Boolean = selected.contains(date)

    override fun isSelectedRangeInterval(date: LocalDate): Boolean {
        if(selectionMode !is SelectionMode.Range) return false
        val min = selected.min()
        val max = selected.max()
        return date.betweenInterval(min, max)
    }

    override fun changeSelected(date: LocalDate) {
        when(selectionMode){
            is SelectionMode.Single -> {
                if(selected.contains(date))
                    selected.clear()
                else{
                    selected.clear()
                    selected.add(date)
                }
            }
            is SelectionMode.Multiply -> {
                selected.addOrRemove(date)
            }
            is SelectionMode.Range -> {
                if(selected.size == 2 && !selected.contains(date))
                    selected.clear()
                if(selected.contains(date))
                   selected.remove(date)
                else
                   selected.add(date)
            }
        }
    }

    override fun getSelectionResult(): SelectionResult {
        if(selected.isEmpty()) return SelectionResult.None

        return when(selectionMode){
            is SelectionMode.Single -> SelectionResult.Single(selected.first())
            is SelectionMode.Multiply -> SelectionResult.Multiple(selected)
            is SelectionMode.Range -> {
                val min = selected.min()
                val max = selected.max()
                if(min == max)
                    return SelectionResult.Single(min)
                SelectionResult.Range(min, max)
            }
        }
    }

    override fun isActiveDay(date: LocalDate): Boolean = activeDay == date

    override fun isEnabled(date: LocalDate): Boolean = !disableDays(date)
}

